package com.tools.web.work.excel.poi;

import com.tools.common.container.AbsOwnList;
import com.tools.common.io.IOKit;
import com.tools.common.object.Note;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 导出 Excel 文件的构建对象
 * */
@Note("导出 Excel 文件的构建对象")
public final class ExcelExportBuilder {

    @Note("即将要导出的目标 Excel 文件")
    private Workbook workbook;

    @Note("当前使用中的 Sheet 的索引")
    private int currentUseSheetIndex = 0;

    @Note("Sheet 页构建列表")
    private List<SheetExportBuilder> sheetExportBuilderList;

    @Note("导出 Excel 文件的类型")
    private ExcelTypeEnum excelType = ExcelTypeEnum.XSSF;

    /* ************************************************************************************************************
     *
     *      构造器
     *
     * ************************************************************************************************************
     * */

    public ExcelExportBuilder(SheetExportBuilder sheetExportBuilder) {
        this(ExcelTypeEnum.XSSF, sheetExportBuilder);
    }

    public ExcelExportBuilder(SheetExportBuilder... sheetExportBuilderArray) {
        this(ExcelTypeEnum.XSSF, sheetExportBuilderArray);
    }

    public ExcelExportBuilder(List<SheetExportBuilder> sheetExportBuilderList) {
        this(ExcelTypeEnum.XSSF, sheetExportBuilderList);
    }

    public ExcelExportBuilder(AbsOwnList<SheetExportBuilder> sheetBuilderList) {
        this(ExcelTypeEnum.XSSF, sheetBuilderList);
    }

    public ExcelExportBuilder(ExcelTypeEnum excelType, SheetExportBuilder sheetExportBuilder) {
        private_initWorkbook(excelType);
        private_initSheetList(sheetExportBuilder);
        this.sheetExportBuilderList = new ArrayList<>(1);
        this.sheetExportBuilderList.add(sheetExportBuilder);
    }

    public ExcelExportBuilder(ExcelTypeEnum excelType, SheetExportBuilder... sheetExportBuilderArray) {
        private_initWorkbook(excelType);
        private_initSheetList(sheetExportBuilderArray);
    }

    public ExcelExportBuilder(ExcelTypeEnum excelType, List<SheetExportBuilder> sheetExportBuilderList) {
        private_initWorkbook(excelType);
        private_initSheetList(sheetExportBuilderList);
    }

    public ExcelExportBuilder(ExcelTypeEnum excelType, AbsOwnList<SheetExportBuilder> sheetBuilderList) {
        private_initWorkbook(excelType);
        private_initSheetList(sheetBuilderList);
    }

    public static ExcelExportBuilder of(SheetExportBuilder sheetExportBuilder) {
        return new ExcelExportBuilder(sheetExportBuilder);
    }

    public static ExcelExportBuilder of(SheetExportBuilder... sheetExportBuilderArray) {
        return new ExcelExportBuilder(sheetExportBuilderArray);
    }

    public static ExcelExportBuilder of(List<SheetExportBuilder> sheetExportBuilderList) {
        return new ExcelExportBuilder(sheetExportBuilderList);
    }

    public static ExcelExportBuilder of(AbsOwnList<SheetExportBuilder> sheetBuilderList) {
        return new ExcelExportBuilder(sheetBuilderList);
    }

    public static ExcelExportBuilder of(ExcelTypeEnum excelType, SheetExportBuilder sheetExportBuilder) {
        return new ExcelExportBuilder(excelType, sheetExportBuilder);
    }

    public static ExcelExportBuilder of(ExcelTypeEnum excelType, SheetExportBuilder... sheetExportBuilderArray) {
        return new ExcelExportBuilder(excelType, sheetExportBuilderArray);
    }

    public static ExcelExportBuilder of(ExcelTypeEnum excelType, List<SheetExportBuilder> sheetExportBuilderList) {
        return new ExcelExportBuilder(excelType, sheetExportBuilderList);
    }

    public static ExcelExportBuilder of(ExcelTypeEnum excelType, AbsOwnList<SheetExportBuilder> sheetBuilderList) {
        return new ExcelExportBuilder(excelType, sheetBuilderList);
    }

    @Override
    public String toString() {
        return "ExcelExportBuilder{" +
                "excelType=" + excelType +
                ", workbook=" + workbook +
                ", currentUseSheetIndex=" + currentUseSheetIndex +
                ", sheetBuilderList=" + sheetExportBuilderList +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ExcelExportBuilder that = (ExcelExportBuilder) o;
        return Objects.equals(workbook, that.workbook) && excelType == that.excelType;
    }

    @Override
    public int hashCode() {
        return Objects.hash(workbook, excelType);
    }

    /* ************************************************************************************************************
     *
     *      工具方法
     *
     * ************************************************************************************************************
     * */

    public ExcelTypeEnum getExcelType() {
        return excelType;
    }

    public int getCurrentUseSheetIndex() {
        return currentUseSheetIndex;
    }

    public ExcelExportBuilder useSheet(int index) {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        if(index >= 0 && index < numberOfSheets) {
            this.currentUseSheetIndex = index;
            return this;
        }
        throw new ArrayIndexOutOfBoundsException("工作表数量为 " + numberOfSheets
                + "，当前要使用的表索引: " + this.currentUseSheetIndex);
    }

    public ExcelExportBuilder nextSheet() {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        int index = this.currentUseSheetIndex + 1;
        if(index < numberOfSheets) {
            this.currentUseSheetIndex = index;
        }
        return this;
    }

    public ExcelExportBuilder previousSheet() {
        int numberOfSheets = this.workbook.getNumberOfSheets();
        int index = this.currentUseSheetIndex - 1;
        if(index >= 0 && index < numberOfSheets) {
            this.currentUseSheetIndex = index;
        }
        return this;
    }

    public ExcelExportBuilder data(List<?> data) {
        Sheet sheet = this.workbook.getSheetAt(this.currentUseSheetIndex);
        SheetExportBuilder builder = this.sheetExportBuilderList.get(this.currentUseSheetIndex);
        ExcelKit.buildData(data, sheet, builder, this.workbook);
        return this;
    }

    public ExcelExportBuilder mergeCell() {
        SheetExportBuilder builder = this.sheetExportBuilderList.get(this.currentUseSheetIndex);
        Sheet sheet = this.workbook.getSheetAt(this.currentUseSheetIndex);
        ExcelKit.defaultMergeTableHandle(builder.getMergeCellIndexMap(), sheet);
        return this;
    }

    public void write(OutputStream out) {
        IOKit.writeWorkbook(this.workbook, out);
    }

    /* ************************************************************************************************************
     *
     *      私有逻辑
     *
     * ************************************************************************************************************
     * */

    @Note("初始化 Workbook 对象")
    private void private_initWorkbook(ExcelTypeEnum excelType) {
        if(excelType == null) throw new NullPointerException("Excel 类型枚举实例不能为 null");
        this.workbook = ExcelKit.newWorkbook(excelType);
        this.excelType = excelType;
    }

    @Note("根据 SheetExportBuilder 对象的包装参数构建 Excel 的 Sheet 页")
    private void private_initSheetList(SheetExportBuilder sheetExportBuilder) {
        if(sheetExportBuilder == null) throw new NullPointerException("Sheet 页构建对象为 null");
        Sheet sheet = ExcelKit.newSheet(this.workbook, sheetExportBuilder.getSheetName());
        ExcelKit.buildSheetTableHead(sheet, this.workbook, sheetExportBuilder);
    }

    @Note("根据多个 SheetExportBuilder 对象的包装参数构建 Excel 的 Sheet 页")
    private void private_initSheetList(SheetExportBuilder... sheetExportBuilderArray) {
        if(sheetExportBuilderArray == null) throw new IllegalArgumentException("至少需要一个以上的 SheetBuilder 对象参数");
        int length = sheetExportBuilderArray.length;
        if(length == 0) throw new IllegalArgumentException("至少需要一个以上的 SheetBuilder 对象参数");
        this.sheetExportBuilderList = new ArrayList<>(length);
        for (SheetExportBuilder builder : sheetExportBuilderArray) {
            private_initSheetList(builder);
            this.sheetExportBuilderList.add(builder);
        }
    }

    @Note("根据多个 SheetExportBuilder 对象的包装参数构建 Excel 的 Sheet 页")
    private void private_initSheetList(List<SheetExportBuilder> sheetExportBuilderList) {
        if(sheetExportBuilderList != null && !sheetExportBuilderList.isEmpty()) {
            this.sheetExportBuilderList = new ArrayList<>(sheetExportBuilderList.size());
            for (SheetExportBuilder builder : sheetExportBuilderList) {
                private_initSheetList(builder);
                this.sheetExportBuilderList.add(builder);
            }
            return;
        }
        throw new IllegalArgumentException("至少需要一个以上的 SheetBuilder 对象参数");
    }

    @Note("根据多个 SheetExportBuilder 对象的包装参数构建 Excel 的 Sheet 页")
    private void private_initSheetList(AbsOwnList<SheetExportBuilder> sheetBuilderList) {
        if(sheetBuilderList == null || sheetBuilderList.isEmpty()) {
            throw new IllegalArgumentException("至少需要一个以上的 SheetBuilder 对象参数");
        }
        this.sheetExportBuilderList = new ArrayList<>(sheetBuilderList.size());
        for (SheetExportBuilder builder : sheetBuilderList) {
            private_initSheetList(builder);
            this.sheetExportBuilderList.add(builder);
        }
    }
}
